//#include "includes/streamer"
//#include "includes/foreach"
//#include "includes/audio"

//===========colors===========
#define COLOR_OOC 0xE0FFFFAA
#define TEAM_AZTECAS_COLOR 0x01FCFFC8
#define TEAM_BLUE_COLOR 0x8D8DFF00
#define COLOR_ALLDEPT 0xFF8282AA
#define COLOR_YELLOW 0xFFFF00FF 
#define RADIO_MESSAGE 0x8dffb000
#define JOB_MESSAGE 0x52adbbFF
#define DEPT_MESSAGE 0xd482ffAA
#define ADMIN_MESSAGE 0xf1fd2aFF
#define OOC_MESSAGE 0xa1cc82FF
#define FAMILY_MESSAGE 0x01FCFFC8
#define MASTER_MESSAGE 0xddddc1FF
#define PM_INCOMING_COLOR     0xFFFF22AA
#define PM_OUTGOING_COLOR     0xFFCC2299
#define COLOR_OOC 0xE0FFFFAA

#define HELPER_CHAT_COLOR 0xEEDD82FF
#define COLOR_GRAD1 0xB4B5B7FF
#define COLOR_GRAD2 0xBFC0C2FF
#define COLOR_GRAD3 0xCBCCCEFF
#define COLOR_GRAD4 0xD8D8D8FF
#define COLOR_GRAD5 0xE3E3E3FF
#define COLOR_GRAD6 0xF0F0F0FF
#define COLOR_GREY 0xAFAFAFAA
#define COLOR_GREEN 0x33AA33FF
#define COLOR_RED 0xAA3333FF
#define COLOR_ORANGERED 0xFF4500FF
#define COLOR_LIGHTRED 0xFF6347AA
#define COLOR_LIGHTBLUE 0x33CCFFAA
#define COLOR_LIGHTGREEN 0x9ACD32AA
#define COLOR_YELLOW2 0xF5DEB3AA
#define COLOR_WHITE 0xFFFFFFAA
#define COLOR_FADE1 0xE6E6E6E6
#define COLOR_FADE2 0xC8C8C8C8
#define COLOR_FADE3 0xAAAAAAAA
#define COLOR_FADE4 0x8C8C8C8C
#define COLOR_FADE5 0x6E6E6E6E
#define COLOR_PURPLE 0xC2A2DAAA
#define COLOR_PURPLES 0xC2A2DAFF
#define COLOR_DBLUE 0x2641FEAA
#define COLOR_NEWS 0xFFA500AA
#define COLOR_BLACK 0x000000FF
#define OBJECTIVE_COLOR 0x64000064
#define TEAM_GREEN_COLOR 0xFFFFFFAA
#define TEAM_JOB_COLOR 0xFFB6C1AA
#define TEAM_HIT_COLOR 0xFFFFFF00
#define COLOR_ADD 0x63FF60AA
#define TEAM_GROVE_COLOR 0x00D900C8
#define TEAM_VAGOS_COLOR 0xFFC801C8
#define TEAM_BALLAS_COLOR 0xD900D3C8
#define TEAM_CYAN_COLOR 0xFF8282AA
#define TEAM_ORANGE_COLOR 0xFF830000
#define TEAM_COR_COLOR 0x39393900
#define TEAM_BAR_COLOR 0x00D90000
#define TEAM_TAT_COLOR 0xBDCB9200
#define TEAM_CUN_COLOR 0xD900D300
#define TEAM_STR_COLOR 0x01FCFF00
#define COLOR_INVIS 0xAFAFAF00
#define CG 0xB8860BAA
#define COLOUR_MONEY_GOOD 0xFFFF00AA // Yellow - Money
#define COLOUR_MONEY_BAD 0xDAA520AA // Yellow - Money
//*****************************
#define MAX_STRING 255

#define Loop(%1,%2) \
for(new %1;%1<=%2;%1++)

//forward split(const strsrc[], strdest[][], delimiter);
forward ini_GetKey( line[] );
forward ini_GetValue( line[] );
forward IsCorrectName(name[]);
forward Float:GetDistanceBetweenPlayers(p1,p2);
forward DebugPlayerLog(playerid,string[]);
forward DebugLog(string[]);
/*
public split(const strsrc[], strdest[][], delimiter)
{
	new i, li;
	new aNum;
	new len;
	while(i <= strlen(strsrc))
	{
	    if(strsrc[i]==delimiter || i==strlen(strsrc))
		{
	        len = strmid(strdest[aNum], strsrc, li, i, 128);
	        strdest[aNum][len] = 0;
	        li = i+1;
	        aNum++;
		}
		i++;
	}
	return 1;
}*/

stock ini_GetKey( line[] )
{
	new keyRes[255];
	keyRes[0] = 0;
    if ( strfind( line , "=" , true ) == -1 ) return keyRes;
    strmid( keyRes , line , 0 , strfind( line , "=" , true ) , sizeof( keyRes) );
    return keyRes;
}

stock ini_GetValue( line[] )
{
	new valRes[255];
	valRes[0]=0;
	if ( strfind( line , "=" , true ) == -1 ) return valRes;
	strmid( valRes , line , strfind( line , "=" , true )+1 , strlen( line ) , sizeof( valRes ) );
	return valRes;
}

public IsCorrectName(name[])
{
	new len = strlen(name);
	if (len<3 || len>MAX_PLAYER_NAME) return 0;
	for(new i=0; i<len; i++)
	{
		if ((name[i] != '[') &&
		(name[i] != ']') &&
		(name[i] != '_') &&
		(name[i] < 'A' || name[i] > 'Z') &&
		(name[i] < 'a' || name[i] > 'z') &&
		(name[i] < '0' || name[i] > '9')
		) return 0;
	}
	return 1;
}

public Float:GetDistanceBetweenPlayers(p1,p2)
{
	new Float:x1,Float:y1,Float:z1,Float:x2,Float:y2,Float:z2;
	if(!IsPlayerConnected(p1) || !IsPlayerConnected(p2))
	{
		return -1.00;
	}
	GetPlayerPos(p1,x1,y1,z1);
	GetPlayerPos(p2,x2,y2,z2);
	return floatsqroot(floatpower(floatabs(floatsub(x2,x1)),2)+floatpower(floatabs(floatsub(y2,y1)),2)+floatpower(floatabs(floatsub(z2,z1)),2));
}

stock IsNumeric(const string[])
{
	for (new i = 0, j = strlen(string); i < j; i++)
	{
		if (string[i] > '9' || string[i] < '0') return 0;
	}
	return 1;
}

stock ReturnUser(text[], playerid = INVALID_PLAYER_ID)
{
	new pos = 0;
	while (text[pos] < 0x21) // Strip out leading spaces
	{
		if (text[pos] == 0) return INVALID_PLAYER_ID; // No passed text
		pos++;
	}
	new userid = INVALID_PLAYER_ID;
	if (IsNumeric(text[pos])) // Check whole passed string
	{
		// If they have a numeric name you have a problem (although names are checked on id failure)
		userid = strval(text[pos]);
		if (userid >=0 && userid < MAX_PLAYERS)
		{
			if(!IsPlayerConnected(userid))
			{
				/*if (playerid != INVALID_PLAYER_ID)
				{
					SendClientMessage(playerid, 0xFF0000AA, "User not connected");
				}*/
				userid = INVALID_PLAYER_ID;
			}
			else
			{
				return userid; // A player was found
			}
		}
		/*else
		{
			if (playerid != INVALID_PLAYER_ID)
			{
				SendClientMessage(playerid, 0xFF0000AA, "Invalid user ID");
			}
			userid = INVALID_PLAYER_ID;
		}
		return userid;*/
		// Removed for fallthrough code
	}
	// They entered [part of] a name or the id search failed (check names just incase)
	new len = strlen(text[pos]);
	new count = 0;
	new name[MAX_PLAYER_NAME];
	for (new i = 0; i < MAX_PLAYERS; i++)
	{
		if (IsPlayerConnected(i))
		{
			GetPlayerName(i, name, sizeof (name));
			if (strcmp(name, text[pos], true, len) == 0) // Check segment of name
			{
				if (len == strlen(name)) // Exact match
				{
					return i; // Return the exact player on an exact match
					// Otherwise if there are two players:
					// Me and MeYou any time you entered Me it would find both
					// And never be able to return just Me's id
				}
				else // Partial match
				{
					count++;
					userid = i;
				}
			}
		}
	}
	if (count != 1)
	{
		if (playerid != INVALID_PLAYER_ID)
		{
			if (count)
			{
				SendClientMessage(playerid, 0xFF0000AA, "Multiple users found, please narrow earch");
			}
			else
			{
				SendClientMessage(playerid, 0xFF0000AA, "No matching user found");
			}
		}
		userid = INVALID_PLAYER_ID;
	}
	return userid; // INVALID_USER_ID for bad return
}
stock Float:Distance3D(Float:PointA[], Float:PointB[], bool:sqrt = true)
{
	new Float:Dist[4];

	for (new i = 0; i < 3; i++)
	{
	    Dist[i] = PointA[i] - PointB[i];
	    Dist[i] *= Dist[i];
	}

	Dist[3] = Dist[0] + Dist[1] + Dist[2];

	return sqrt ? floatsqroot(Dist[3]) : Dist[3];
}
stock Float:Angle2D(Float:PointA[], Float:PointB[])
{
	new bool:A_LS_B[2], Float:Dist[2], Float:Angle;

	for (new i = 0; i < 2; i++)
	{
	    A_LS_B[i] = PointA[i] < PointB[i];
	    Dist[i] = A_LS_B[i] ? PointB[i] - PointA[i] : PointA[i] - PointB[i];
	}

	Angle = atan2(Dist[1],Dist[0]);
	Angle = A_LS_B[0] ? 270.0 + Angle : 90.0 - Angle;
	Angle = A_LS_B[1] ? Angle : 180.0 - Angle;

	return Angle;
}
stock right(source[], len)
{
	new retval[MAX_STRING], srclen;
	srclen = strlen(source);
	strmid(retval, source, srclen - len, srclen, MAX_STRING);
	return retval;
}

stock left(source[], len)
{
	new retval[MAX_STRING], srclen;
	srclen = strlen(source);
	strmid(retval, source, srclen + len, srclen, MAX_STRING);
	return retval;
}

public DebugPlayerLog(playerid,string[])
{
	new name[MAX_PLAYER_NAME];
	new entry[255];
	new h,m,s,y,ms,d;
	gettime(h,m,s);
	getdate(y,ms,d);
	GetPlayerName(playerid, name, sizeof(name));
	format(entry, sizeof(entry), "%d:%d(%d/%d) %s: %s\r\n",h,m,d,ms,name,string);
	new File:hFile;
	hFile = fopen("gf/logs/debug.log", io_append);
	fwrite(hFile, entry);
	fclose(hFile);
}
public DebugLog(string[])
{
	new entry[255];
	new h,m,s,y,ms,d;
	gettime(h,m,s);
	getdate(y,ms,d);
	format(entry, sizeof(entry), "%d:%d(%d/%d) %s\r\n",h,m,d,ms,string);
	new File:hFile;
	hFile = fopen("gf/logs/debug.log", io_append);
	fwrite(hFile, entry);
	fclose(hFile);
}

stock strtok(const string[], &index)
{
	new length = strlen(string);
	while ((index < length) && (string[index] <= ' '))
	{
		index++;
	}

	new offset = index;
	new result[20];
	while ((index < length) && (string[index] > ' ') && ((index - offset) < (sizeof(result) - 1)))
	{
		result[index - offset] = string[index];
		index++;
	}
	result[index - offset] = EOS;
	return result;
}

stock strrest(const string[], &index)
{
	new length = strlen(string);
	while ((index < length) && (string[index] <= ' '))
	{
		index++;
	}
	new offset = index;
	new result[128];
	while ((index < length) && ((index - offset) < (sizeof(result) - 1)))
	{
		result[index - offset] = string[index];
		index++;
	}
	result[index - offset] = EOS;
	return result;
}

stock IsKeyJustDown(key, newkeys, oldkeys)
{
	if((newkeys & key) && !(oldkeys & key)) return 1;
	return 0;
}

stock formatime()
{
	new day, month, year;
	new hour, minute;
	new frmtm[25];
	getdate(year, month, day);
	gettime(hour, minute);
	format(frmtm, 25, "%02d/%02d/%d %02d:%02d", year, month, day, hour, minute);
	return frmtm;
}

stock CheckName(name[])
{
	new names[2][16];
	new l = strlen(name);
	new i, sc;
	while(i <= l)
	{
	    if(name[i]== '_')
		{
		sc++;
		}
		i++;
	}
	if (sc != 1) return 0;
	sscanf(name, "p<_>s[16]s[16", names[0],names[1]);
	if(!IsGood(names[0]) || !IsGood(names[1])) return 0;
	return 1;
}

stock IsGood(name[])
{
	if(strlen(name)<3) return 0;
	if(name[0]<'A' || name[0]>'Z') return 0;
	for(new i=1; i<strlen(name); i++)
	{
		if(name[i]<'a' || name[i]>'z') return 0;
	}
	return 1;
}

forward SetCarCameraPos(playerid,carid);
public SetCarCameraPos(playerid,carid)
{
	new Float:camvX,Float:camvY,Float:camvZ,Float:camvA,Float:camX,Float:camY,Float:camZ;
	new rad=6;
	new Float:up=2.0;
	if(IsABoat(carid))
		rad=16,up=4.0;
	GetVehiclePos(carid,camvX,camvY,camvZ);
	GetVehicleZAngle(carid,camvA);
	camX = camvX + rad*floatsin(-camvA, degrees);
	camY = camvY + rad*floatcos(-camvA, degrees);
	camZ = camvZ + up;
	SetPlayerCameraPos(playerid,camX,camY,camZ);
	SetPlayerCameraLookAt(playerid,camvX,camvY,camvZ,CAMERA_MOVE);
	return 1;
}

stock FixSpaces(str[])
{
	new retstr[255];
	if(str[0]!=' ')
	{
		format(retstr,sizeof(retstr)," %s",str);
		return retstr;
	}
	for(new i=0;i<strlen(str);i++)
	{
		if(str[i] != ' ')
		{
			strdel(str, 0,i-1);
		}
	}
	format(retstr,sizeof(retstr),"%s",str);
	return retstr;
}

stock Float:GetPlayerSpeed(playerid)
{
	new Float:vPos[3];
    GetVehicleVelocity(GetPlayerVehicleID(playerid), vPos[0], vPos[1], vPos[2]);
	return floatmul(floatsqroot(floatadd(floatpower(vPos[0], 2), floatadd(floatpower(vPos[1], 2), floatpower(vPos[2], 2)))), 200);
}

stock oGetPlayerName(playerid)
{
	new str[MAX_PLAYER_NAME];
    GetPlayerName(playerid,str,sizeof(str));
    return str;
}
stock GetPlayerNameEx(playerid)
{
    new string[MAX_PLAYER_NAME];
    GetPlayerName(playerid,string,MAX_PLAYER_NAME);
    new str[MAX_PLAYER_NAME];
    strmid(str,string,0,strlen(string),MAX_PLAYER_NAME);
    for(new i = 0; i < MAX_PLAYER_NAME; i++)
    {
        if (str[i] == '_') str[i] = ' ';
    }
    return str;
}

stock GetPlayerInitials(playerid)
{
    new string[MAX_PLAYER_NAME], str[MAX_PLAYER_NAME], lol;
    GetPlayerName(playerid,string,MAX_PLAYER_NAME);
    strmid(str,string,0,strlen(string),MAX_PLAYER_NAME);
    for(new i = 0; i < MAX_PLAYER_NAME; i++)
	{
		if (str[i] == '_') lol = i+1;
	}
    format(string, sizeof(string), "%c%c", str[0], str[lol]);
    return string;
}
/*
forward IsNearObject(playerid, objid, Float:radius);
public IsNearObject(playerid, objid, Float:radius)
{
	new Float:ox, Float:oy, Float:oz;
	GetDynamicObjectPos(objid, ox, oy, oz);
	if(IsPlayerInRangeOfPoint(playerid,radius, ox, oy, oz)) return 1;
	else return 0;
}*/

forward IsPlayerInArea(playerid, Float:minx, Float:maxx, Float:miny, Float:maxy);
public IsPlayerInArea(playerid, Float:minx, Float:maxx, Float:miny, Float:maxy)
{
	new Float:x, Float:y, Float:z;
	GetPlayerPos(playerid,x,y,z);
	if (x>minx && x<maxx && y>miny && y<maxy) return 1;
	return 0;
}

stock Float:GetDistanceBetweenPoints(Float:x1,Float:y1,Float:z1,Float:x2,Float:y2,Float:z2)
{
	return floatadd(floatadd(floatsqroot(floatpower(floatsub(x1,x2),2)),floatsqroot(floatpower(floatsub(y1,y2),2))),floatsqroot(floatpower(floatsub(z1,z2),2)));
}

//forward GetClosestCarInRadiusNearPlayer(playerid, Float:radius,bit=0);
stock GetClosestCarInRadiusNearPlayer(playerid, Float:radius,bit=0)
{
    new cid;
	if(bit==1)cid=GetPlayerVehicleID(playerid);
	new Float:x, Float:y, Float:z, Float:vx, Float:vy, Float:vz, id = -1, Float:dist;
	GetPlayerPos(playerid, x, y, z);
	dist = radius+1;
	switch(bit)
	{
		case 0:
		{
			Loop(idx,2000)
			{
			    GetVehiclePos(idx, vx, vy, vz);
			    if(IsPlayerInRangeOfPoint(playerid, radius, vx, vy, vz))
			    {
			        new Float:distance = GetDistanceBetweenPoints(x,y,z,vx,vy,vz);
					if(dist > distance)
					{
						id = idx;
						dist = distance;
					}
			    }
			}
		}
		case 1:
		{
		    Loop(idx,2000)
			{
			    if(idx!=cid)
			    {
				    GetVehiclePos(idx, vx, vy, vz);
				    if(IsPlayerInRangeOfPoint(playerid, radius, vx, vy, vz))
				    {
				        new Float:distance = GetDistanceBetweenPoints(x,y,z,vx,vy,vz);
						if(dist > distance)
						{
							id = idx;
							dist = distance;
						}
				    }
			    }
			}
		}
	}
	return id;
}

stock Antiexploit(string[])
{
	for(new x=0; x < strlen(string); x++)
	{
		if(string[x]=='<'||string[x]=='>'||string[x]=='='||string[x]=='/'||string[x]=='''||string[x]=='['||string[x]==']'||string[x]=='{'||string[x]=='}'||string[x]=='('||string[x]==')'||string[x]==','||string[x]=='+'||string[x]=='*')
		{
			string[x] = ' ';
		}
	}
	return string;
}

stock IsVehicleDrivingBackwards(vehicleid) // By Joker
{
	new
		Float:Float[3]
	;
	if(GetVehicleVelocity(vehicleid, Float[1], Float[2], Float[0]))
	{
		GetVehicleZAngle(vehicleid, Float[0]);
		if(Float[0] < 90)
		{
			if(Float[1] > 0 && Float[2] < 0) return true;
		}
		else if(Float[0] < 180)
		{
			if(Float[1] > 0 && Float[2] > 0) return true;
		}
		else if(Float[0] < 270)
		{
			if(Float[1] < 0 && Float[2] > 0) return true;
		}
		else if(Float[1] < 0 && Float[2] < 0) return true;
	}
	return false;
}